
#include <iostream>
#include <memory>


// #define CIRCULAR_REFER
/* weak_ptr配合shared_ptr解决循环引用的问题
*/

/* 野指针是指指针指向的内存空间已经被释放，此时这个指针被称为野指针
*/


/*
 * shared_ptr固然好用，但是它也会有问题存在。假设我们要使用定义一个双向链表，如果我们想要让创建出来的链表的节点都定义成shared_ptr智能指针，
*  那么也需要将节点内的_pre和_next都定义成shared_ptr的智能指针。如果定义成普通指针，那么就不能赋值给shared_ptr的智能指针。
 *
*/

/*
 * unique_ptr
        独占的智能指针

        unique_ptr是一个独占型的智能指针，不能将其赋值给另一个unique_ptr
        unique_ptr可以指向一个数组
        unique_ptr需要确定删除器的类型
        使用方法
        基本与shared_ptr一致，只不过不能多个unique_ptr指向同一个内存对象，从而规避了很多问题，但是也少了很多使用场景。

   weak_ptr
        弱引用的智能指针

        什么是weak_ptr
        share_ptr虽然已经很好用了，但是有一点share_ptr智能指针还是有内存泄露的情况，当两个对象相互使用一个shared_ptr成员变量指向对方，会造成循环引用，使引用计数失效，从而导致内存泄漏。

        weak_ptr解决了什么问题
        weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的shared_ptr， weak_ptr只是提供了对管理对象的一个访问手段。

        weak_ptr为什么能解决问题。
        weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。

*/
using namespace std;

#ifdef CIRCULAR_REFER
struct Node
{
    shared_ptr<Node> prev;
    shared_ptr<Node> next;
};

/*
 *   当创建出node1和node2智能指针对象时，引用计数都是1.
 *   当node1的next指向node2所指向的资源时，node2的引用计数就+1，变成2，node2的pre指向noede1所指向的资源时，node1的引用计数+1，变成2.
 *   当这两个智能指针使用完后，调用析构函数，引用计数都-1，都变成1，由于引用计数不为0，所以node1和node2所指向的对象不会被释放。
 *   当node1所指向的资源释放需要当node2中的_prev被销毁，就需要node2资源的释放，node2所指向的资源释放就需要当node1中的_next被销毁，就需要node1资源的释放。
 *      因此node1和node2都有对方的“把柄”，这两个就造成循环引用现象，最终这node1和node2资源就不会进行释放。
*
*/

/*
 * c++库中存在weak_ptr类型的智能指针。
 *  weak_ptr类的对象它可以指向shared_ptr，并且不会改变shared_ptr的引用计数。
 * 一旦最后一个shared_ptr被销毁时，对象就会被释放。
 * weak_ptr对象指向shared_ptr对象时，不会增加shared_ptr中的引用计数，
 * 因此当node1销毁掉时，则node1指向的空间就会被销毁掉，node2类似，所以weak_ptr指针可以很好解决循环引用的问题。
 * 所以在定义双向链表或者在二叉树等有多个指针的时候,如果想要将该类型定义成智能指针，那么结构体内的指针需要定义成weak_ptr类型的指针，防止循环引用的出现。
*/
#else
struct Node
{
    weak_ptr<Node> prev;
    weak_ptr<Node> next;
};
#endif


int main(int argc, char *argv[])
{

    shared_ptr<Node> node1(new Node);
    shared_ptr<Node> node2(new Node);

    std::cout << "node1.use_count: " << node1.use_count() << std::endl;
    std::cout << "node2.use_count: " << node2.use_count() << std::endl;
    node1->next = node2;
    node2->prev = node1;

    std::cout << "node1.use_count: " << node1.use_count() << std::endl;
    std::cout << "node2.use_count: " << node2.use_count() << std::endl;

    std::cout << "WEAK node2.use_count: " << node2->prev.use_count() << std::endl;

    std::cout << "******************" << std::endl;

    // shared_ptr 
    {
        shared_ptr<int> ppp(new int(89));
        std::cout << "use_count: " << ppp.use_count() << std::endl;
        weak_ptr<int> ppp1(ppp);

        std::cout << "use_count: " << ppp.use_count() << std::endl;

        shared_ptr<int> ppp2 = ppp;

        std::cout << "use_count: " << ppp.use_count() << std::endl;

        std::cout << "*******************" << std::endl;
    }
    
    
    return 0;

}